using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Xml.Linq;
using LightCAD.MathLib;
namespace LightCAD.Core.Elements
{
    public class LcLine : LcCurve2d
    {
        public Line2d Line => (this.Curve as Line2d);
        public Vector2 Start { get=> Line.Start; set { this.Line.Start = value; } }
        public Vector2 End { get => Line.End; set { this.Line.End = value; } }

        public LcLine()
        {
            this.Type = BuiltinElementType.Line;
            this.Curve = new Line2d();
        }
        public LcLine(Vector2 start, Vector2 end) : this()
        {
            this.Start = start;
            this.End = end;
        }
        public LcLine(double startX, double startY, double endX, double endY) : this(new Vector2(startX,startY),new Vector2(endX,endY))
        {
                                
        }
        public double Length=>this.Line.Length;
        [JsonIgnore]
        public double Angle=>(this.End - this.Start).Angle();

        [JsonIgnore]
        public double DeltaX=>this.End.X - this.Start.X;
      
        [JsonIgnore]
        public double DeltaY=> this.End.Y - this.Start.Y;
   

        public override LcElement ApplyMatrix(Matrix3 matrix)
        {
            this.Start = matrix.MultiplyPoint(this.Start);
            this.End = matrix.MultiplyPoint(this.End);
            return this;
        }
       
        public override LcElement Clone()
        {
            var clone = Document.CreateObject<LcLine>();
            clone.Copy(this);
            return clone;
        }

        public void Set(Vector2 start = null, Vector2 end = null, bool fireChangedEvent = true)
        {
            //PropertySetter:Start,End
            if (!fireChangedEvent)
            {
                if (start != null) this.Start = start;
                if (end != null) this.End = end;
            }
            else
            {
                bool chg_start = (start != null && start != this.Start);
                if (chg_start)
                {
                    OnPropertyChangedBefore(nameof(Start), this.Start, start);
                    var oldValue = this.Start;
                    this.Start = start;
                    OnPropertyChangedAfter(nameof(Start), oldValue, this.Start);
                }
                bool chg_end = (end != null && end != this.End);
                if (chg_end)
                {
                    OnPropertyChangedBefore(nameof(End), this.End, end);
                    var oldValue = this.End;
                    this.End = end;
                    OnPropertyChangedAfter(nameof(End), oldValue, this.End);
                }
            }
        }
        public override Box2 GetBoundingBox()
        {
            return new Box2().SetFromPoints(this.Start, this.End);
        }
        public override Box2 GetBoundingBox(Matrix3 matrix)
        {
            return new Box2().SetFromPoints(matrix.MultiplyPoint(this.Start), matrix.MultiplyPoint(this.End));
        }
        public override Vector2 LineCrossLine(LcLine element)
        {
            Line2d line1 = new Line2d(this.Start, this.End);
            Line2d line2 = new Line2d((element as LcLine).Start, (element as LcLine).End);
            
           return GeoUtils.GetCrossVector(line1, line2);
        }
        public override Vector2 LineCrossLine(Line2d element)
        {
            Line2d line1 = new Line2d(this.Start, this.End);
            Line2d line2 = new Line2d(element.Start, element.End);

            return GeoUtils.GetCrossVector(line1, line2);
        }
        public override List<Vector2> GetCrossVectorByLine(Line2d element)
        {
            Line2d line1 = new Line2d(this.Start, this.End);
            Line2d line2 = element;
            Vector2 point = GeoUtils.GetCrossVector(line1, line2);
            List<Vector2> ps = new List<Vector2>();
            ps.Add(point);
            return ps;  
            //if(point != null)
            //{
            //        if (GeoUtils.IsPointOnLineExtension(line2.Start, line2.End, point))
            //        {
            //            return null;
            //        }
            //        else
            //        {
            //            ps.Add(point);
            //            return ps;

            //        }
            //}
            //else
            //{
            //    return null;
            //}
            
        }
        public override List<Vector2> GetCrossVectorByArc(Arc2d arc)
        {
 
            Arc2d arc2D = new Arc2d();
            arc2D.Center = arc.Center;
            arc2D.Radius = arc.Radius;
            arc2D.StartAngle = arc.StartAngle;
            arc2D.EndAngle = arc.EndAngle;
            arc2D.IsClockwise = false;

            List<Vector2> points = GeoUtils.GetCrossLineArc(this.Start, this.End, arc2D.Center, arc2D.Radius);

            //List<Vector2> endpoints = new List<Vector2>();
            //foreach (var item in points)
            //{
            //    //&& GeoUtils.IsPointOnArcExtension(arc, item)
            //    if (!Arc2d.PointInArc(item, arc.Startp, arc.Endp, arc.Center))
            //    {
            //        endpoints.Add(item);
            //    }
            //}
            //return endpoints;
            //return GeoUtils.ArcCrossLine(arc2D, line1);
            return points;
        }
        public override List<Vector2> GetCrossVectorByCircle(Circle2d ele)
        {
            List<Vector2> ps = new List<Vector2>();
            ps = GeoUtils.GetCrossCircleLine(this.Start, this.End, ele.Center, ele.Radius);
            return ps;
        }
        public override bool PointInElement(Vector2 point, double epsilon = 0.001)
        {
            double sx =this.Start.X; 
            double sy =this.Start.Y;
            double ex = this.End.X;
            double ey = this.End.Y;
            double k;
            double b;
            double maxx, minx, maxy, miny;
            if (sx <= ex)
            {
                maxx = ex;
                minx = sx;
            }
            else
            {
                maxx = sx;
                minx = ex;
            }
            if (sy <= ey)
            {
                maxy = ey;
                miny = sy;
            }
            else
            {
                maxy = sy;
                miny = ey;
            }

            if (ex != sx)
            {
                k = (ey - sy) * 1.0 / (ex - sx);
                b = sy - k * sx;
                if (Math.Abs(point.Y - (point.X * k + b)) < epsilon)
                {
                    if (point.X <= maxx && point.X >= minx)
                    {
                        if (point.Y <= maxy && point.Y >= miny)
                        {
                            return true;
                        }
                        else { return false; }
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
            else
            {
                    if (point.Y <= maxy && point.Y >= miny)
                    {
                        return true;
                    }
                    else { return false; }
            }
        }


        public override void WriteProperties(Utf8JsonWriter writer, JsonSerializerOptions soptions)
        {
            writer.WriteVector2dProperty(nameof(this.Start), this.Start);
            writer.WriteVector2dProperty(nameof(this.End), this.End);
            writer.WriteStringProperty(nameof(this.Color), this.Color);
        }
        public override void ReadProperties(ref JsonElement jele)
        {
            this.Start = jele.ReadVector2dProperty(nameof(Start));
            this.End = jele.ReadVector2dProperty(nameof(End));
           this.Color=jele.ReadStringProperty(nameof(Color));
        }

        //public override List<Vector2> GetCrossVectorByLcArc(LcArc arc2D)
        //{
        //    List<Vector2> points = GetCrossLineArc(new Line2d(this.Start, this.End),arc2D.Center,arc2D.Radius);
        //    return points;
        //}
        
    }
}